﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;

public interface AdController
{
	
	/// <summary>
	/// 初始化
	/// </summary>
	void Init();

	/// <summary>
	/// 视频广告
	/// </summary>
	void LoadVideoAd();
	void PlayVideoAd();

	/// <summary>
	/// 插页广告
	/// </summary>
	void LoadInterstitialAd();
	void ShowInterstitialAd();
    
	/// <summary>
	/// Banner广告
	/// </summary>
	void ShowBanner();
	void HideBanner();

	/// <summary>
	/// 释放
	/// </summary>
	void Release();
	
	// Called when an Banner ad request has successfully loaded.
	Action<string>onBannerAdLoaded { get; set; }
	// Called when an Banner ad request failed to load.
	Action<string>onBannerAdFailedToLoad { get; set; }
	Action<string> onBannerShowSuc { get; set; }
	Action<string> onBannerShowFailed { get; set; }
	// Called when an Banner ad is clicked.
	Action<string>onBannerAdOpening{ get; set; }
	// Called when the user returned from the app after an Banner ad click.
	Action<string>onBannerAdClosed { get; set; }
	// Called when the Banner ad click caused the user to leave the application.
	Action<string>onBannerAdLeavingApplication { get; set; }
	
	// Called when an Interstitial ad request has successfully loaded.
	Action<string>onInterstitialAdLoaded { get; set;}
	// Called when an Interstitial ad request failed to load.
	Action<string>onInterstitialAdFailedToLoad { get; set;}
	Action<string>onInterstitialAdSuc { get; set;}
	Action<string>onInterstitialAdFail { get; set;}
	// Called when an Interstitial ad is shown.
	Action<string>onInterstitialAdOpening { get; set;}
	// Called when the Interstitial ad is closed.
	Action<string>onInterstitialAdClosed { get; set;}
	// Called when the Interstitial ad click caused the user to leave the application.
	Action<string>onInterstitialAdLeavingApplication { get; set;}
	
	Action<string>onVideoAdLoaded  { get; set;}
	// Called when an ad request failed to load.
	Action<string>onVideoAdFailedToLoad { get; set;}
	// Called when an ad is shown.
	Action onVideoAdOpening  { get; set;}
	// Called when an ad request failed to show.
	Action<string>onVideoAdFailedToShow  { get; set;}
	// Called when the user should be rewarded for interacting with the ad.
	Action<string>onVideoPlaySuc { get; set;}
	// Called when the ad is closed.
	Action onVideoAdClosed { get; set;}
	
	bool IsVideoReady { get; }

	bool IsInterstitialReady { get; }

	/// <summary>
	/// 释放banner广告事件
	/// </summary>
	void ReleaseBannerEvent();
	
	/// <summary>
	/// 释放Interstitial广告事件
	/// </summary>
	void ReleaseInterstitialEvent();
	
	/// <summary>
	/// 释放Video广告事件
	/// </summary>
	void ReleaseVideoEvent();

	void LoadBanner();
}



public  class AdManager
{
	/// <summary>
	/// 广告列表,依次播放广告
	/// </summary>
	private List<AdController> m_AdControllers = new List<AdController>();

	private const int NotInitIndex = -1;
	
	/// <summary>
	/// 视频广告序号
	/// </summary>
	private int m_CurVideoIndex = NotInitIndex;

	/// <summary>
	/// 插页广告序号
	/// </summary>
	private int m_CurInterstitialIndex = NotInitIndex;

	/// <summary>
	/// Banner广告序号
	/// </summary>
	int curBannerIndex
	{
		get { return PlayerPrefs.GetInt(BannerIndexKey,NotInitIndex); }
		set { PlayerPrefs.SetInt(BannerIndexKey,value);}
	}

	private const string BannerIndexKey = "BannerAdIndex";

	public bool isVideoReady
    {
        get
		{
			if (m_CurVideoIndex>= 0 && m_CurVideoIndex < m_AdControllers.Count)
			{
				AdController curController = m_AdControllers[m_CurVideoIndex];
				return curController.IsVideoReady;
			}
			return false;
		}
    }
	public bool isInterstitialReady
	{
		get
		{
			if (m_CurInterstitialIndex >= 0 && m_CurInterstitialIndex < m_AdControllers.Count)
			{
				AdController curController = m_AdControllers[m_CurInterstitialIndex];
				return curController.IsInterstitialReady;
			}
			return false;
		}
	}

	public AdManager()
    {
		Debug.Log($"new ad manager");
    }

	/// <summary>
	/// 初始化
	/// </summary>
	public void Init(List<AdController> adControllers)
	{
		m_AdControllers = new List<AdController>(adControllers);

		foreach (AdController adController in m_AdControllers)
		{
			adController.Init();
		}

		if (m_CurVideoIndex == NotInitIndex)
		{
			m_CurVideoIndex = UnityEngine.Random.Range(0, m_AdControllers.Count);
		}
		if (m_CurInterstitialIndex == NotInitIndex)
		{
			m_CurInterstitialIndex = UnityEngine.Random.Range(0, m_AdControllers.Count);
		}
		if (curBannerIndex == NotInitIndex)
		{
			curBannerIndex = UnityEngine.Random.Range(0, m_AdControllers.Count);
		}

		Debug.Log($"ad controllers count:{adControllers.Count}");
		//if (curBannerIndex < m_AdControllers.Count)
		//{
		//	GameDebug.Log($"LoadBanner curBannerIndex:{curBannerIndex} ");
		//	m_AdControllers[curBannerIndex].LoadBanner();
		//}
	}

	#region Video

	private Action<string> m_OnVideoPlayFailed;
	private Action m_OnVideoClosed;
	private Action m_OnVideoPlaySuc;

	public void LoadVideoAd()
	{
#if DEBUG
		GameDebug.Log($"LoadVideoAd :{m_CurVideoIndex}");
#endif
		if (m_CurVideoIndex >= 0 && m_CurVideoIndex < m_AdControllers.Count)
		{
			AdController curController = m_AdControllers[m_CurVideoIndex];
			curController.LoadVideoAd();
			curController.onVideoAdLoaded = this.OnVideoAdLoaded;
			curController.onVideoAdFailedToLoad = this.OnVideoAdFailedToLoad;
			curController.onVideoAdOpening = this.OnVideoAdOpening;
			curController.onVideoAdFailedToShow = this.OnVideoAdFailedToShow;
			curController.onVideoAdClosed = this.OnVideoAdClosed;
			curController.onVideoPlaySuc = this.OnVideoAdUserEarnedReward;
		}
		else
		{
			GameDebug.LogError($"out of range,m_CurVideoIndex:{m_CurVideoIndex}   m_AdControllers.Count:{ m_AdControllers.Count}");
		}
	}

	private bool m_GetVideoRes;
	private float videoTimeOutSec = 30;
	private float m_BeginPlayVideoTime;
	/// <summary>
	/// 视频广告
	/// </summary>
	public void PlayVideoAd(Action onSuc,Action onSkip,Action<string> onFail)
	{
#if DEBUG
		GameDebug.Log($"PlayVideoAd :{m_CurVideoIndex}");
#endif
		m_GetVideoRes = false;
		m_BeginPlayVideoTime = Time.time;
		
		m_OnVideoPlaySuc = onSuc;
		m_OnVideoClosed = onSkip;
		m_OnVideoPlayFailed = onFail;
		
		if (m_CurVideoIndex >= 0 && m_CurVideoIndex < m_AdControllers.Count)
		{
			m_AdControllers[m_CurVideoIndex].PlayVideoAd();
		}
		else
		{
			GameDebug.LogError($"out of range,m_CurVideoIndex:{m_CurVideoIndex}   m_AdControllers.Count:{ m_AdControllers.Count}");
			onFail?.Invoke("no ad");
		}
		
		DoActionDelay.DelayAction(videoTimeOutSec, () =>
		{
			if (!m_GetVideoRes && Time.time - m_BeginPlayVideoTime >= videoTimeOutSec)
			{
				GameDebug.LogError($"播放广告没有返回");
				
				NextVideoController();
			}
		});
	}

	void NextVideoController()
	{
		m_GetVideoRes = true;
		
		if (m_AdControllers.Count > 1)
		{
			if (m_CurVideoIndex >= 0 && m_CurVideoIndex < m_AdControllers.Count)
			{
				m_AdControllers[m_CurVideoIndex].ReleaseVideoEvent();
			}

			m_CurVideoIndex++;
			m_CurVideoIndex %= m_AdControllers.Count;

			GameDebug.Log($"加载下一类广告：{m_AdControllers[m_CurVideoIndex].GetType().Name}");
		}

		LoadVideoAd();
	}
	
	public void OnVideoAdLoaded(string msg)
	{
		MonoBehaviour.print("OnVideoAdLoaded event received");
	}

	public void OnVideoAdFailedToLoad(string msg)
	{
		GameDebug.LogError(
			"OnVideoAdFailedToLoad event received with message: "
			+msg);
	}

	public void OnVideoAdOpening()
	{
		MonoBehaviour.print("OnVideoAdOpening event received");
		
	}

	public void OnVideoAdFailedToShow(string msg)
	{
		MonoBehaviour.print(
			"OnVideoAdFailedToShow event received with message: "
			+ msg);
		
		var action = m_OnVideoPlayFailed;
		action?.Invoke(msg);
		m_OnVideoPlayFailed = null;
			
		NextVideoController();
	}

	public void OnVideoAdClosed()
	{
		MonoBehaviour.print("OnVideoAdClosed event received");
		
		if (!m_GetVideoRes)
		{
			var action = m_OnVideoClosed;
			action?.Invoke();
			m_OnVideoClosed = null;
		}
		else
		{
			MonoBehaviour.print("Video play suc ,ignore close event");
		}
		
		NextVideoController();
	}

	public void OnVideoAdUserEarnedReward(string msg)
	{
		MonoBehaviour.print(
			"OnUserEarnedReward event received for "
			+ msg);
		
		var action = m_OnVideoPlaySuc;
		action?.Invoke();
		m_OnVideoPlaySuc = null;
		
		NextVideoController();
	}
	
#endregion
	#region Interstitial
	private Action<string> m_OnInterstitialPlayFailed;
	private Action m_OnInterstitialClosed;
	private Action m_OnInterstitialPlaySuc;

	private bool m_ShowInterititialSuc;
	public void LoadInterstitialAd()
	{
#if DEBUG
		GameDebug.Log($"LoadInterstitialAd :{m_CurInterstitialIndex}");
#endif
		
		if (m_CurInterstitialIndex >= 0 && m_CurInterstitialIndex < m_AdControllers.Count)
		{
			AdController curController = m_AdControllers[m_CurInterstitialIndex];
			curController.LoadInterstitialAd();
			curController.onInterstitialAdLoaded = this.OnInterstitialAdLoaded;
			curController.onInterstitialAdFailedToLoad = this.OnInterstitialAdFailedToLoad;
			curController.onInterstitialAdSuc = this.OnInterstitialAdSuc;
			curController.onInterstitialAdFail = this.OnInterstitialAdFailedToShow;
			curController.onInterstitialAdOpening = this.OnInterstitialAdOpened;
			curController.onInterstitialAdClosed = this.OnInterstitialAdClosed;
			curController.onInterstitialAdLeavingApplication = this.OnInterstitialAdLeavingApplication;
		}
		else
		{
			GameDebug.LogError($"out of range,m_CurVideoIndex:{m_CurInterstitialIndex}   m_AdControllers.Count:{ m_AdControllers.Count}");
		}
	}
	
	/// <summary>
	/// 插页广告
	/// </summary>
	public void ShowInterstitialAd(Action onSuc,Action onSkip,Action<string> onFail)
	{
#if DEBUG
		GameDebug.Log($"ShowInterstitialAd :{m_CurInterstitialIndex}");
#endif
		m_ShowInterititialSuc = false;
		
		m_OnInterstitialPlayFailed = onFail;
		m_OnInterstitialClosed = onSkip;
		m_OnInterstitialPlaySuc = onSuc;
		
		if (m_CurInterstitialIndex >= 0 && m_CurInterstitialIndex < m_AdControllers.Count)
		{
			m_AdControllers[m_CurInterstitialIndex].ShowInterstitialAd();
		}
		else
		{
			GameDebug.LogError($"out of range,m_CurVideoIndex:{m_CurInterstitialIndex}   m_AdControllers.Count:{ m_AdControllers.Count}");
			onFail?.Invoke("no ad");
		}

	}


	void NextInterstitialConrtoller()
	{
		if (m_AdControllers.Count > 1)
		{
			if (m_CurInterstitialIndex >= 0 && m_CurInterstitialIndex < m_AdControllers.Count)
			{
				m_AdControllers[m_CurInterstitialIndex].ReleaseInterstitialEvent();
			}

			m_CurInterstitialIndex++;
			m_CurInterstitialIndex %= m_AdControllers.Count;
		}
		m_AdControllers[m_CurInterstitialIndex].LoadInterstitialAd();
	}
	
	public void OnInterstitialAdLoaded(string msg)
	{
		MonoBehaviour.print("OnInterstitialAdLoaded event received");
	}

	public void OnInterstitialAdFailedToLoad(string msg)
	{
		MonoBehaviour.print("OnInterstitialAdFailedToLoad event received with message: " + msg);
		
	}
	public void OnInterstitialAdSuc(string msg)
	{
		MonoBehaviour.print("OnInterstitialAdSuc event received");
		
		m_ShowInterititialSuc = true;
		
		NextInterstitialConrtoller();
		
		var action = this.m_OnInterstitialPlaySuc;
		action?.Invoke();
		m_OnInterstitialPlaySuc = null;
	}
	public void OnInterstitialAdFailedToShow(string msg)
	{
		MonoBehaviour.print("OnInterstitialAdFailedToShow event received");
		
		NextInterstitialConrtoller();
		
		var action = this.m_OnInterstitialPlayFailed;
		action?.Invoke(msg);
		m_OnInterstitialPlayFailed = null;
	}
	public void OnInterstitialAdOpened(string msg)
	{
		MonoBehaviour.print("OnInterstitialAdOpened event received");
	}

	public void OnInterstitialAdClosed(string msg)
	{
		MonoBehaviour.print("OnInterstitialAdClosed event received");
		
		NextInterstitialConrtoller();

		if (!m_ShowInterititialSuc)
		{
			var action = this.m_OnInterstitialClosed;
			action?.Invoke();
			m_OnInterstitialClosed = null;
		}
		else
		{
			MonoBehaviour.print("InterstitialAd showed suc,ignore close event");

		}
	}

	public void OnInterstitialAdLeavingApplication(string msg)
	{
		MonoBehaviour.print("OnInterstitialAdLeavingApplication event received");
	}
	
	#endregion



	#region Banner
	
	/// <summary>
	/// Banner广告
	/// </summary>
	public void ShowBanner()
	{
#if DEBUG
		GameDebug.Log($"ShowBanner :{curBannerIndex}");
#endif
		if (m_AdControllers.Count <= 0)
			return;

		if (curBannerIndex >= m_AdControllers.Count)
		{
			GameDebug.LogError($"out of range,curBannerIndex:{curBannerIndex}   m_AdControllers.Count:{ m_AdControllers.Count}");
			curBannerIndex %= m_AdControllers.Count;
		}

		if (curBannerIndex >= 0 && curBannerIndex < m_AdControllers.Count)
		{
			AdController curController = m_AdControllers[curBannerIndex];
			curController.onBannerAdLoaded = this.OnBannerAdLoaded;
			curController.onBannerAdFailedToLoad = this.OnBannerAdFailedToLoad;
			curController.onBannerShowSuc = this.OnBannerAdShown;
			curController.onBannerShowFailed = this.OnBannerAdFailedToShow;
			curController.onBannerAdOpening = this.OnBannerAdOpened;
			curController.onBannerAdClosed = this.OnBannerAdClosed;
			curController.onBannerAdLeavingApplication = this.OnBannerAdLeavingApplication;
			curController.ShowBanner();
		}
		else
		{
			GameDebug.LogError($"out of range,curBannerIndex:{curBannerIndex}   m_AdControllers.Count:{ m_AdControllers.Count}");
		}
	}


	public void HideBanner()
	{
#if DEBUG
		GameDebug.Log($"HideBanner :{curBannerIndex}");
#endif
		
		if (curBannerIndex >= 0 && curBannerIndex < m_AdControllers.Count)
		{
			m_AdControllers[curBannerIndex].HideBanner();
		}
		else
		{
			GameDebug.LogError($"out of range,curBannerIndex:{curBannerIndex}   m_AdControllers.Count:{ m_AdControllers.Count}");
        }

        NextBannerController();
    }

	void NextBannerController()
	{
		if (m_AdControllers.Count > 1)
		{
			if (curBannerIndex >= 0 && curBannerIndex < m_AdControllers.Count)
			{
				m_AdControllers[curBannerIndex].ReleaseBannerEvent();
			}

			curBannerIndex++;
			curBannerIndex %= m_AdControllers.Count;
		}

		m_AdControllers[curBannerIndex].LoadBanner();
	}
	
	public void Release()
	{
		foreach (AdController adController in m_AdControllers)
		{
			adController.Release();
		}
	}
	
	public void OnBannerAdLoaded(string msg)
	{
		MonoBehaviour.print("OnBannerAdLoaded event received");
	}


	public void OnBannerAdFailedToLoad(string msg)
	{
		GameDebug.LogError("OnBannerAdFailedToLoad event received with message: " + msg);
		
	}
	private void OnBannerAdShown(string obj)
	{
		NextBannerController();
	}
	private void OnBannerAdFailedToShow(string obj)
	{
		NextBannerController();
	}
	public void OnBannerAdOpened(string msg)
	{
		GameDebug.LogError("OnBannerAdOpened event received");
	}

	public void OnBannerAdClosed(string msg)
	{
		MonoBehaviour.print("OnBannerAdClosed event received");

		NextBannerController();
	}

	public void OnBannerAdLeavingApplication(string msg)
	{
		MonoBehaviour.print("OnBannerAdLeavingApplication event received");
	}

	#endregion
	
}